﻿package com.toncen.samepms.system.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import ognl.Ognl;
import ognl.OgnlContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.toncen.samepms.basic.domain.User;
import com.toncen.samepms.common.AbstractAdviceDispatcher;
import com.toncen.samepms.common.AbstractDomain;
import com.toncen.samepms.common.ComitConstant;
import com.toncen.samepms.common.EmailAdviceDispatcher;
import com.toncen.samepms.common.SystemMessageAdviceDispatcher;
import com.toncen.samepms.util.OfficeUtils;
import com.opensymphony.xwork2.ActionContext;
import com.sky.common.ognl.OgnlUtils;
import com.sky.common.string.StringUtils;
import com.sky.dataimport.DynamicCellDataCell;
import com.sky.dataimport.DynamicCellDataRow;
import com.sky.dataimport.DynamicRowDataCell;
import com.sky.dataimport.DynamicRowDataRow;
import com.sky.dataimport.StaticDataCell;
import com.sky.dataimport.StaticDataRow;
import com.sky.dataimport.datatype.IntegerDataType;

/**
 * 描述：undefined表SYSTEM_ADVICE的domain文件
 * 
 * @author tch
 */
@DynamicRowDataRow(title = "动态行智能通知", sheetIndex = 1, startRowIndex = 2, startCellIndex = 1, inserted = false)
@DynamicCellDataRow(title = "动态列智能通知", sheetIndex = 1, startRowIndex = 2, startCellIndex = 2, inserted = false)
@StaticDataRow(title = "静态行列智能通知", sheetIndex = 1)
public class Advice extends AbstractDomain {
	private Log logger = LogFactory.getLog(this.getClass());

	/**
	 * 序列号
	 */
	private static final long serialVersionUID = 1348024453180L;

	/**
	 * 通知名
	 */
	@StaticDataCell(rowIndex = 1, cellIndex = 1, title = "通知名")
	@DynamicRowDataCell(cellIndex = 1, title = "通知名", require = false)
	@DynamicCellDataCell(rowIndex = 1, title = "通知名", require = false)
	private String name;

	/**
	 * 通知分组
	 */
	@StaticDataCell(rowIndex = 2, cellIndex = 2, title = "通知分组")
	@DynamicRowDataCell(cellIndex = 2, title = "通知分组", require = false)
	@DynamicCellDataCell(rowIndex = 2, title = "通知分组", require = false)
	@IntegerDataType(msg = "必须为整数类型")
	private int adviceGroup;

	/**
	 * 业务对象
	 */
	@StaticDataCell(rowIndex = 3, cellIndex = 3, title = "业务对象")
	@DynamicRowDataCell(cellIndex = 3, title = "业务对象", require = false)
	@DynamicCellDataCell(rowIndex = 3, title = "业务对象", require = false)
	private String domainClass;

	/**
	 * 通知条件
	 */
	@StaticDataCell(rowIndex = 4, cellIndex = 4, title = "通知条件")
	@DynamicRowDataCell(cellIndex = 4, title = "通知条件", require = false)
	@DynamicCellDataCell(rowIndex = 4, title = "通知条件", require = false)
	private String condition;

	/**
	 * 通知对象
	 */
	@StaticDataCell(rowIndex = 5, cellIndex = 5, title = "通知对象")
	@DynamicRowDataCell(cellIndex = 5, title = "通知对象", require = false)
	@DynamicCellDataCell(rowIndex = 5, title = "通知对象", require = false)
	private String target;

	/**
	 * 通知主题
	 */
	@StaticDataCell(rowIndex = 6, cellIndex = 6, title = "通知主题")
	@DynamicRowDataCell(cellIndex = 6, title = "通知主题", require = false)
	@DynamicCellDataCell(rowIndex = 6, title = "通知主题", require = false)
	private String subject;

	/**
	 * 通知内容
	 */
	@StaticDataCell(rowIndex = 7, cellIndex = 7, title = "通知内容")
	@DynamicRowDataCell(cellIndex = 7, title = "通知内容", require = false)
	@DynamicCellDataCell(rowIndex = 7, title = "通知内容", require = false)
	private String content;

	/**
	 * 默认通知方式
	 */
	private int defaultMode = 1;

	/**
	 * 顺序
	 */
	@StaticDataCell(rowIndex = 8, cellIndex = 8, title = "顺序")
	@DynamicRowDataCell(cellIndex = 8, title = "顺序", require = false)
	@DynamicCellDataCell(rowIndex = 8, title = "顺序", require = false)
	@IntegerDataType(msg = "必须为整数类型")
	private int sequence = 10;

	/**
	 * 标签起始标记
	 */
	public static final String OGNL_START_TAG = "%{";

	/**
	 * 标签结束标记
	 */
	public static final String OGNL_END_TAG = "}%";

	/**
	 * 业务对象上一次的状态值
	 */
	public static final String PARAMETER_LASTSTATE = "lastState";

	/**
	 * 当前登录用户对象
	 */
	public static final String PARAMETER_USER = "user";

	/**
	 * 通知发布者
	 */
	private static final List<AbstractAdviceDispatcher> adviceDispatchers = new ArrayList<AbstractAdviceDispatcher>(5);

	static {
		adviceDispatchers.add(new EmailAdviceDispatcher());// 注册邮件通知发布者
		adviceDispatchers.add(new SystemMessageAdviceDispatcher());// 系统消息通知发布者
		OgnlUtils.registerAlias("@@", "@" + OfficeUtils.class.getName() + "@");
	}

	/**
	 * 注册智能通知发布者
	 * 
	 * @param adviceDispatcher
	 * @return
	 */
	public static boolean registAdviceDispatcher(AbstractAdviceDispatcher adviceDispatcher) {
		return adviceDispatchers.add(adviceDispatcher);
	}

	/**
	 * @return the defaultMode
	 */
	public int getDefaultMode() {
		return defaultMode;
	}

	/**
	 * @param defaultMode
	 *            the defaultMode to set
	 */
	public void setDefaultMode(int defaultMode) {
		this.defaultMode = defaultMode;
	}

	public Advice() {
		super();
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the adviceGroup
	 */
	public int getAdviceGroup() {
		return adviceGroup;
	}

	/**
	 * @param adviceGroup
	 *            the adviceGroup to set
	 */
	public void setAdviceGroup(int adviceGroup) {
		this.adviceGroup = adviceGroup;
	}

	/**
	 * @return the domainClass
	 */
	public String getDomainClass() {
		return domainClass;
	}

	/**
	 * @param domainClass
	 *            the domainClass to set
	 */
	public void setDomainClass(String domainClass) {
		this.domainClass = domainClass;
	}

	/**
	 * @return the condition
	 */
	public String getCondition() {
		return condition;
	}

	/**
	 * @param condition
	 *            the condition to set
	 */
	public void setCondition(String condition) {
		this.condition = condition;
	}

	/**
	 * @return the target
	 */
	public String getTarget() {
		return target;
	}

	/**
	 * @param target
	 *            the target to set
	 */
	public void setTarget(String target) {
		this.target = target;
	}

	/**
	 * @return the subject
	 */
	public String getSubject() {
		return subject;
	}

	/**
	 * @param subject
	 *            the subject to set
	 */
	public void setSubject(String subject) {
		this.subject = subject;
	}

	/**
	 * @return the content
	 */
	public String getContent() {
		return content;
	}

	/**
	 * @param content
	 *            the content to set
	 */
	public void setContent(String content) {
		this.content = content;
	}

	/**
	 * @return the sequence
	 */
	public int getSequence() {
		return sequence;
	}

	/**
	 * @param sequence
	 *            the sequence to set
	 */
	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	/**
	 * 获取指定后缀的配置参数值
	 * 
	 * @param ognlContext
	 * @param root
	 * @param parameterSuffix
	 * @return
	 * @throws Exception
	 */
	public static String getConfiguration(OgnlContext ognlContext, Object root, String content) throws Exception {
		if (!StringUtils.isEmpty(content)) {
			Set<String> expressionSet = StringUtils.getAllTag(content, OGNL_START_TAG, OGNL_END_TAG);
			Object value;
			for (String expression : expressionSet) {
				value = OgnlUtils.getValue(expression, ognlContext, root);
				content = StringUtils.replaceAll(content, OGNL_START_TAG + expression + OGNL_END_TAG, value.toString());
			}
		}
		return content;
	}

	/**
	 * 获取接收者
	 * 
	 * @param ognlContext
	 * @param root
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public Set<User> getToUsers(OgnlContext ognlContext, Object root) throws Exception {
		Object users = OgnlUtils.getValue(this.getTarget(), ognlContext, root);
		if (users == null) {
			throw new Exception("通知对象[" + this.getTarget() + "]获取值为空，请与系统管理员联系！");
		}
		if (users instanceof User) {
			Set<User> us = new HashSet<User>();
			us.add((User) users);
			return us;
		}
		if (!(users instanceof Collection)) {
			throw new Exception("通知对象[" + this.getTarget() + "]获取值不为[" + Collection.class.getName() + "]类型，请与系统管理员联系！");
		}
		return new HashSet<User>((Collection) users);
	}

	/**
	 * 是否需要通知
	 * 
	 * @param ognlContext
	 * @param adviceContext
	 * @param root
	 * @param objectState
	 * @return
	 * @throws Exception
	 */
	public boolean accept(OgnlContext ognlContext, Object adviceContext, Object root, String objectState) throws Exception {
		Object condition = OgnlUtils.getValue(this.getCondition(), ognlContext, root);
		if (condition == null) {
			throw new Exception("通知条件[" + this.getCondition() + "]获取值为空，请与系统管理员联系！");
		}
		if (!(condition instanceof Boolean)) {
			throw new Exception("通知条件[" + this.getCondition() + "]获取值不为[" + Boolean.class.getName() + "]类型，请与系统管理员联系！");
		}
		return new Boolean(condition.toString());
	}

	/**
	 * 发布通知
	 * 
	 * @param object
	 * @param adviceContext
	 * @param objectState
	 * @return
	 * @throws Exception
	 */
	public String publish(Object object, Object adviceContext, String objectState) throws Exception {
		User user = new User();
		if (ActionContext.getContext() != null && ActionContext.getContext().getSession().get(ComitConstant.USER_SESSION_ATTRIBUTE) != null) {
			user = (User) ActionContext.getContext().getSession().get(ComitConstant.USER_SESSION_ATTRIBUTE);
		}
		OgnlContext ognlContext = (OgnlContext) Ognl.createDefaultContext(null);
		ognlContext.put(PARAMETER_LASTSTATE, objectState);
		ognlContext.put(PARAMETER_USER, user);
		Object root = object;
		StringBuffer result = new StringBuffer();
		if (object.getClass().getName().equals(this.domainClass) // 指定的业务对象
				&& accept(ognlContext, adviceContext, root, objectState)) {// 符合当前通知类型条件
			String subject = getConfiguration(ognlContext, root, this.getSubject());
			String content = getConfiguration(ognlContext, root, this.getContent());
			User fromUser = user;
			Set<User> toUsers = getToUsers(ognlContext, root);
			result.append(send(fromUser, toUsers, subject, content));
		}
		return result.toString();
	}

	/**
	 * @param fromUser
	 * @param toUsers
	 * @param subject
	 * @param content
	 */
	public String send(User fromUser, Set<User> toUsers, String subject, String content) {
		StringBuffer result = new StringBuffer();
		for (AbstractAdviceDispatcher adviceDispatcher : adviceDispatchers) {
			if (this.getDefaultMode() == adviceDispatcher.getMode()) {// 通知方式符合
				result.append("方式：");
				result.append(adviceDispatcher.getMode());
				try {
					result.append("\t结果：");
					result.append(adviceDispatcher.send(this, fromUser, toUsers, subject, content));
				} catch (Exception e) {
					e.printStackTrace();
					logger.error("智能通知【" + this.getName() + "】方式【" + adviceDispatcher.getMode() + "】失败：" + e.getMessage());
					result.append(AbstractAdviceDispatcher.UNSUCCESSFUL);
				}
				result.append(";");
				result.append("\n");
			}
		}
		return result.toString();
	}

}
